#!/usr/bin/python
# -*- coding: UTF-8 -*-
'''
Weather classes
Created on 30 jun 2011

@author: Joakim Lindskog

Copyright (c) 2011 Joakim Lindskog

This file is part of MyGarden.

    MyGarden is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    MyGarden is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with MyGarden.  If not, see <http://www.gnu.org/licenses/>.
'''
import util, random, pyglet
from util import config
from gardenbase import gardensprite
from cocos import actions
from pyglet import gl

class Weather(object):
    '''
    A class for representing weather
    '''
    weathers = None
    current_weather = None
    day_in_month = 1.0
    weather_done = None
    
    def __init__(self, image, change_val):
        self.icon = None
        self.weather_days = 0
        self.change_value = change_val
        self.icon = gardensprite.GardenSprite(util.load_image(image))
        self.is_new_month = False
    
    def changes(self, dt, game):
        '''
        Checks if the weather should change now
        
        @param dt: time elapsed since last check, in seconds
        @type dt: float
        
        @param game: the Game instance
        @type game: Game
        
        @return: whether the weather should change now
        @rtype: boolean
        '''
        check = random.randrange(0,int(dt*10000))
        if check < dt*8000:
            return False
        self.weather_days += dt
        rand = random.randrange(0,100)
        if rand < self.change_value**self.weather_days:
            self.weather_days = 0
            return True
        return False
    
    def update(self, dt, game):
        '''
        Updates the weather
        
        @param dt: time elapsed since last update, in seconds
        @type dt: float
        
        @param game: the Game instance
        @type game: Game
        '''
        # Update temperature
        if self.is_new_month:
            Weather.day_in_month = 0
            self.is_new_month = False
        Weather.day_in_month += dt
        game.base_temperature = config.AVERAGE_SOIL_TEMPS[game.month] \
            + (config.AVERAGE_SOIL_TEMPS[game.month+1] - config.AVERAGE_SOIL_TEMPS[game.month]) \
            * (Weather.day_in_month / config.DAYS_IN_MONTH[game.month])
        game.temperature = game.base_temperature
        
        # Check if weather changes
        if self.changes(dt, game):
            new_weather(game)
            game.gui_layer.update_weather(Weather.current_weather)
            return True
        
        # Let the current weather do what it does
        self.do_weather(dt, game)
        return False
    
    def do_weather(self, dt, game):
        '''
        Lets this weather perform
        
        @param dt: time elapsed since last update, in seconds
        @type dt: float
        
        @param game: the Game instance
        @type game: Game
        '''
        if Weather.weather_done != self:
            Weather.weather_done = self
    
    def new_month(self):
        '''
        Sets a new month
        '''
        self.is_new_month = True
        
    def on_ending(self, game, next_weather):
        '''
        Called when a weather is ending
        
        @param game: the Game instance
        @type game: Game
        
        @param next_weather: the next weather in line
        @type next_weather: Weather
        '''
        pass
    
class Sunny(Weather):
    '''
    Sunny weather
    '''
    
    def __init__(self):
        super(Sunny, self).__init__("sun.png", 3.5)
        
    def do_weather(self, dt, game):
        if Weather.weather_done != self:
            # Possibility of even warmer in june-august
            self.temp_mult = 1+random.randrange(2,7 if game.month > 2 and game.month < 6 else 6)/10.0
        super(Sunny, self).do_weather(dt, game)
        game.temperature = game.base_temperature * self.temp_mult
    
class CloudySunny(Weather):
    '''
    Cloudy with sunny intervals - "default" weather
    '''
    
    def __init__(self):
        super(CloudySunny, self).__init__("cloudandsun.png", 2.8)
    
    def do_weather(self, dt, game):
        super(CloudySunny, self).do_weather(dt, game)
    
class Rainy(Weather):
    '''
    Rain
    '''
    
    def __init__(self):
        super(Rainy, self).__init__("rain.png", 5.5)
        self.rain_effect = gardensprite.GardenSprite(util.load_image('rain_overlay.png'))
        self.rain_effect.position = config.SCREEN_WIDTH/2, config.SCREEN_HEIGHT/2
        
    def do_weather(self, dt, game):
        if Weather.weather_done != self:
            # Might be a little colder
            self.temp_mult = random.randrange(9,11)/10.0
            # Rain effect
            game.add(self.rain_effect, z=249)
            self.rain_effect.do(actions.FadeTo(180, 1))
            pyglet.clock.schedule_interval(self.move_rain_image, 0.08)
            # Rain sound
            game.scene.load_music(util.get_sound_path('rain.ogg'))
            game.scene.play_music(-1, fade_in=2000)
        super(Rainy, self).do_weather(dt, game)
        game.temperature = game.base_temperature * self.temp_mult
        beds = game.garden_layer.beds
        for bed in beds:
            bed.water += 15*dt
            
    def move_rain_image(self, dt):
        '''
        Moves the rain image a random amount in a random direction
        
        @param dt: time elapsed since last check, in seconds
        @type dt: float
        '''
        x = random.randrange(-112, 113)
        y = random.randrange(-42, 43)
        self.rain_effect.position = config.SCREEN_WIDTH/2+x, config.SCREEN_HEIGHT/2+y
            
    def on_ending(self, game, next_weather):
        if next_weather != self:
            self.rain_effect.stop()
            self.rain_effect.do(actions.FadeTo(0, 1)+actions.CallFunc(lambda: self.stop_rain(game)))
            game.scene.stop_music(fade_out=1000)
    
    def stop_rain(self, game):
        '''
        Stops the rain
        
        @param game: the Game instance
        @type game: Game
        '''
        pyglet.clock.unschedule(self.move_rain_image)
        game.remove(self.rain_effect)
    
class Cold(Weather):
    '''
    Cold weather
    '''
    
    def __init__(self):
        super(Cold, self).__init__("cold.png", 7)
        
    def do_weather(self, dt, game):
        if Weather.weather_done != self:
            # Possibility of even colder in march-april or october
            self.temp_mult = random.randrange(6 if game.month == 0 or game.month == 1 or game.month == 7 else 7,9)/10.0
        super(Cold, self).do_weather(dt, game)
        game.temperature = game.base_temperature * self.temp_mult

def new_weather(game):
    '''
    Picks a new weather
    '''
    if not Weather.weathers:
        Weather.weathers = [Rainy(),
                            Cold(),
                            Sunny(),
                            CloudySunny()]
    # Pick new weather
    n_weather = Weather.weathers[random.randrange(0,len(Weather.weathers))]
    # Notify old weather that it's ending
    if Weather.current_weather:
        Weather.current_weather.on_ending(game, n_weather)
    # Set new weather
    Weather.current_weather = n_weather

def get_weather(game):
    '''
    @return: the current weather
    @rtype: Weather
    '''
    if not Weather.current_weather:
        new_weather(game)
    return Weather.current_weather